package com.platform.user.service;

import com.baomidou.mybatisplus.plugins.Page;
import com.platform.bean.JsonResult;
import com.platform.bean.PageInfo;
import com.platform.exception.BadRequestException;
import com.platform.exception.BaseException;
import com.platform.user.dao.UserDao;
import com.platform.user.entity.MyUserDetails;
import com.platform.user.entity.User;
import com.platform.utils.Base64Utils;
import com.platform.utils.ExcelUtils;
import com.platform.utils.PrintMessageUtils;
import com.platform.utils.UploadFileToRemoteUtils;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@Service
@NoArgsConstructor
// UserDetailsService负责根据用户名查找用户,UserDetailsPasswordService负责更新密码,现在把这两个接口封装成MyUserDetailService
// TODO 留给业务模块重写此类（MyUserDetailService），因为这个类需要连接具体数据库，但web模块只提供通用的配置
public class MyUserDetailService implements UserDetailsService, UserDetailsPasswordService {

    @Resource
    private UserDao userDao;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
//    当调用updatePassword()方法时，可以在具体的实现中根据需要进行密码加密,即使用户输入的新密码是明文形式，也可以在该方法内部使用合适的加密方式对密码进行加密并保存到存储中
//    默认使用的是DelegatingPasswordEncoder中的Bcrypt方式加密,如果需要指定用户升级密码的加密方式,就需要在securityConfig中对PasswordEncoder实现并写入spring工厂就行了
//    虽然在其它地方没有调用updatePassword方法,但在用户每次登录成功时,会自动更新用户的密码编码方式,并且存储在数据库中
    public UserDetails updatePassword(UserDetails user, String newPassword) {
////        调用mapper修改数据库中的密码,newPassword是新的密码,包括新的编码方式或者新的密码明文,返回的是判断有没有更新密码的结果
//        Integer result = userDao.updatePassword(user.getUsername(), newPassword);
//        System.out.println("newPassword:" + newPassword);
//        if(result == 1) {
////            如果为1,说明数据库中的密码修改成功,就需要把实体类对象user里面的密码也进行更新
//            ((MyUserDetails) user).getUser().setPassword(newPassword);
//        }
//        return user;
        return null;
    }

    public User queryByUserId(Integer id) {
        return userDao.queryById(id);
    }

    public User touristQueryUserInfoById(Integer id) {
        if (id != null) {
            return userDao.touristQueryUserInfoById(id);
        }
        return null;
    }

    public void deleteUserById(int id) {
        userDao.deleteById(id);
    }

    public void addUserByExcel(MultipartFile file) throws IOException {
        if (file == null) {
            return;
        }
        try {
            List<Map<String, Object>> dataFromExcel = ExcelUtils.getDataFromExcel(file);
            PrintMessageUtils.traverseListMap(dataFromExcel);
            String sql = this.getSqlByColumns("user", dataFromExcel);
            System.out.println(sql);
            // 创建参数 Map
            Map<String, Object> params = new HashMap<>();
            params.put("sql", sql);

            // 执行动态生成的 SQL 语句
            userDao.executeDynamicSql(params);
        } catch (Exception e) {
            throw new BaseException("从Excel导入数据失败！");
        }
    }

    public PageInfo<User> queryUserByPage(Map<String, Object> params) {
        Integer pageIndex = (Integer) params.get("pageIndex");
        Integer pageSize = (Integer) params.get("pageSize");
        Page<Map> page = new Page<>(pageIndex, pageSize);
        List<User> userList = userDao.queryByPage(page, params);
        return new PageInfo<>(pageIndex, pageSize, userDao.countByParams(params), userList);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.queryByUsername(username);
        if(ObjectUtils.isEmpty(user)) {
            return null;
        }
        return new MyUserDetails(user, user.getUsername(), user.getPassword());
    }

    public User queryUserByUsername(String username) {
        if (username == null || username.isEmpty()) {
            throw new BadRequestException("用户名为空");
        }
        return userDao.queryByUsername(username);
    }

    public User addUser(Map<String, Object> params) throws IOException {
        String password = (String) params.get("password");
        String imageBase64 = (String) params.get("imageUrl");

        if (StringUtils.isBlank(imageBase64)) {
            params.put("profilePicture", "http://117.72.40.8/images/lost_and_found/defaultProfilePicture.png");
        } else {
            String profilePicture = saveProfilePictureToUrl(imageBase64);
            params.put("profilePicture", profilePicture);
        }

        params.put("password", passwordEncoder.encode(password));
        params.put("ifBan", "0");
        User user = setUserByParams(params);

        try {
            userDao.insert(user);
        } catch (Exception e) {
            UploadFileToRemoteUtils.deleteFileFromRemoteServer(user.getProfilePicture(), "/opt/docker/apache/www/images/lost_and_found");

        }
//
//        if (userDao.insert(user) != 1) {
//            throw new BaseException("插入用户异常！");
//        }

        return user;
    }

    /**
     * 将base64封面图片转换为url
     *
     * @param profilePicture base64图片
     * @return 图片url
     * @throws IOException 异常
     */
    private String saveProfilePictureToUrl(String profilePicture) throws IOException {
        StringBuilder fileName = new StringBuilder();
        Map<String, String> imageTypeAndCode = Base64Utils.splitImageTypeAndCode(profilePicture);
        String imageType = null;
        String base64Data = null;

        if (imageTypeAndCode != null) {
            imageType = imageTypeAndCode.get("imageType");
            base64Data = imageTypeAndCode.get("base64Data");
        }

        fileName.append(System.currentTimeMillis()).append(".").append(imageType);
        // Base64转文件
        MultipartFile multipartFile = Base64Utils.convertBase64ToMultipart(base64Data, fileName.toString());
        JsonResult jsonResult = UploadFileToRemoteUtils.uploadFileToRemoteServer(multipartFile, "/opt/docker/apache/www/images/lost_and_found");
        return (String) jsonResult.getData();
    }

    private User setUserByParams(Map<String, Object> params) {
        String username = (String) params.get("username");
        String profilePicture = (String) params.get("profilePicture");
        String password = (String) params.get("password");
        String fullName = (String) params.get("fullName");
        int identity = Integer.parseInt((String) params.get("identity"));
        String academy = (String) params.get("academy");
        String major = (String) params.get("major");
        String email = (String) params.get("email");
        String sex = (String) params.get("sex");
        int ifBan = Integer.parseInt((String) params.get("ifBan"));

        User user = new User();
        user.setSex(sex);
        user.setUsername(username);
        user.setPassword(password);
        user.setEmail(email);
        user.setFullName(fullName);
        user.setIdentity(identity);
        user.setMajor(major);
        user.setAcademy(academy);
        user.setIfBan(ifBan);
        user.setProfilePicture(profilePicture);

        return user;
    }

    private String getSqlByColumns(String tableCode, List<Map<String, Object>> dimData) {
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO ").append(tableCode).append(" (");

        // 拼接列名
        Set<String> columns = dimData.get(0).keySet();
        columns.forEach(key -> sql.append(key).append(","));
        sql.setLength(sql.length() - 1); // 去掉最后一个逗号
        sql.append(") VALUES ");

        // 拼接所有行的值
        for (Map<String, Object> row : dimData) {
            sql.append("(");

            for (Map.Entry<String, Object> entry : row.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().toString(); // 强制转换为String
                // System.out.println("Key: " + key + ", Value: " + value);

                if (value != null && !Objects.equals(value, "")) {
                    switch (key) {
                        case "identity": {
                            if (value.equals("学生")) {
                                sql.append("'").append("0").append("',");
                            } else {
                                sql.append("'").append("1").append("',");
                            }
                            break;
                        }
                        case "password": {
                            sql.append("'").append(passwordEncoder.encode(value)).append("',");
                            break;
                        }
                        default: {
                            sql.append("'").append(value).append("',");
                            break;
                        }
                    }
                } else {
                    sql.append("NULL,");
                }
                
            }
            sql.setLength(sql.length() - 1); // 去掉最后一个逗号
            sql.append("),");
        }
        sql.setLength(sql.length() - 1); // 去掉最后一个逗号

        return sql.toString();
    }
}
